package stream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.MediaStreamTrack;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RtpParameters;
import org.webrtc.RtpTransceiver;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class LocalStream {
    private static final Logger logger = LoggerFactory.getLogger(LocalStream.class);
    private Constraints constraints;
    private MediaStream mediaStream;
    private AudioSource audioSource;
    private AudioTrack audioTrack;
    private VideoSource videoSource;
    private VideoTrack videoTrack;
    private PeerConnection pc;

    public LocalStream() {

    }

    public LocalStream getUserMedia(PeerConnectionFactory peerConnectionFactory) {
        if (constraints == null) {
            constraints = new Constraints().getDefaultConstraints();
        }
        mediaStream = peerConnectionFactory.createLocalMediaStream(UUID.randomUUID().toString());
        audioSource = peerConnectionFactory.createAudioSource(new MediaConstraints());
        audioTrack = peerConnectionFactory.createAudioTrack(UUID.randomUUID().toString(), audioSource);
        mediaStream.addTrack(audioTrack);

        videoSource = peerConnectionFactory.createVideoSource(false);
        videoTrack = peerConnectionFactory.createVideoTrack(UUID.randomUUID().toString(), videoSource);
        mediaStream.addTrack(videoTrack);
        return this;
    }

    public MediaStreamTrack getTrack(Kind kind) {
        if (Kind.AUDIO == kind) {
            if (mediaStream.audioTracks != null) {
                return mediaStream.audioTracks.get(0);
            }
            return null;
        }
        if (mediaStream.videoTracks != null) {
            return mediaStream.videoTracks.get(0);
        }
        return null;
    }



    void publishTrack(MediaStreamTrack mediaStreamTrack) {
        List<String> streamIds = new ArrayList<>();
        if ("video".equals(mediaStreamTrack.kind())) {
            streamIds.add(mediaStreamTrack.id());
            VideoConstraints videoConstraints = VideoConstraints.getVideoConstraints().get(constraints.getResolution());
            RtpParameters.Encoding encoding = new RtpParameters.Encoding(UUID.randomUUID().toString(), true, 1D);
            assert videoConstraints != null;
            encoding.maxFramerate = videoConstraints.getEncodings().getMaxFrameRate();
            encoding.maxBitrateBps = videoConstraints.getEncodings().getMaxBitrate();
            encoding.rid = videoConstraints.getEncodings().getRid();
            encoding.scaleResolutionDownBy = videoConstraints.getEncodings().getScaleResolutionDownBy();
            List<RtpParameters.Encoding> encodings = new ArrayList<>();
            encodings.add(encoding);
            pc.addTransceiver(mediaStreamTrack, new RtpTransceiver
                    .RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY, streamIds));
        }  else {
            pc.addTransceiver(mediaStreamTrack,
                    new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY, streamIds));
        }

    }





    public void publish(PeerConnection pc) {
        this.pc = pc;
        this.mediaStream.videoTracks.forEach(this::publishTrack);
        this.mediaStream.audioTracks.forEach(this::publishTrack);

    }


    public MediaStream getMediaStream() {
        return mediaStream;
    }

    public Constraints getConstraints() {
        return constraints;
    }


    public AudioSource getAudioSource() {
        return audioSource;
    }

    public AudioTrack getAudioTrack() {
        return audioTrack;
    }

    public VideoSource getVideoSource() {
        return videoSource;
    }

    public VideoTrack getVideoTrack() {
        return videoTrack;
    }


    public void setMediaStream(MediaStream stream) {
        this.mediaStream = stream;
    }
}
